package com.jihu.rpc.server;

import com.huge.rpc.Request;
import com.huge.rpc.Response;
import com.huge.rpc.codec.Decoder;
import com.huge.rpc.codec.Encoder;
import com.huge.rpc.common.utils.ReflectionUtils;
import com.huge.rpc.handler.RequestHandler;
import com.huge.rpc.server.TransportServer;
import com.jihu.rpc.server.config.RpcServerConfig;
import com.jihu.rpc.server.instance.ServiceInstance;
import com.jihu.rpc.server.invoke.ServiceInvoke;
import com.jihu.rpc.server.manager.ServiceManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;

/**
 * @author jihu
 * @date 2020/10/14
 */
@Slf4j
public class RpcServer {

    private RpcServerConfig config;
    private TransportServer net;
    private Encoder encoder;
    private Decoder decoder;
    private ServiceManager serviceManager;
    private ServiceInvoke serviceInvoke;

    public RpcServer(RpcServerConfig config) {
        this.config = config;

        //net
        this.net = ReflectionUtils.newInstance(
                config.getTransportCLss());
        this.net.init(config.getPort(),this.handler);

        //codec
        this.encoder = ReflectionUtils.newInstance(
                config.getEncodeClass());
        this.decoder = ReflectionUtils.newInstance(
                config.getDecoderClass());

        // service
        this.serviceManager = new ServiceManager();
        this.serviceInvoke = new ServiceInvoke();

    }

    public <T> void register (Class<T> interfaceClas,T bean){
        serviceManager.register(interfaceClas,bean);
    }

    public void start(){
        this.net.start();
    }

    public void stop(){
        this.net.stop();
    }

    private RequestHandler handler = (recive, toResp) -> {
        Response response =  new Response();
        // todo
        try {
            byte[] inBytes = IOUtils.readFully(recive,recive.available());
            Request request = decoder.decode(inBytes,Request.class);
            log.debug("get request:{}",request);

            ServiceInstance serviceInstance = serviceManager.lookup(request);
            Object resultData = serviceInvoke.invoke(serviceInstance, request);
            response.setData(resultData);
        } catch (IOException e) {
           log.warn(e.getMessage(),e);
           response.setCode(1);
           response.setMessage("RpcServer got error: " +
                   e.getClass().getName()+
                   " : "+e.getMessage());
        }finally {
            byte[] encode = encoder.encode(response);
            try {
                toResp.write(encode);
                log.info("response client");
            } catch (IOException e) {
                log.warn(e.getMessage(),e);
            }
        }
    };
}
